﻿using System;
using System.Collections.ObjectModel;
using System.Windows.Automation;
using ProdControls.Interfaces;
using ProdControls.UIAPatterns;
using ProdControls.Utility;
using ProdControls.Verification;
using ProdLogging;

namespace ProdControls.Bridges
{
    internal static class ListBridge
    {
        /// <summary>
        ///   Gets the list of all items.
        /// </summary>
        public static AutomationElementCollection ListItemsHook(this IList extension,
                                                                BaseProdControl control)
        {
            return SelectionPatternHelper.ListItems(control.UIAElement);
        }

        /// <summary>
        ///   Gets an array containing all selected items.
        /// </summary>
        public static AutomationElement[] SelectedItemsHook(this IList extension,
                                                            BaseProdControl control)
        {
            return SelectionPatternHelper.SelectedItems(control.UIAElement);
        }

        public static int ItemCountHook(this IList extension,
                                        BaseProdControl control)
        {
            return ListItemsHook(extension, control).Count;
        }

        public static int SelectedItemCountHook(this IList extension,
                                                BaseProdControl control)
        {
            return ListItemsHook(extension, control).Count;
        }

        /// <summary>
        ///   Adds the list item to the current selection.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="index"> The zero-based index of the item to select. </param>
        public static void AddToSelectionHook(this IList extension, BaseProdControl control, int index)
        {
            try
            {
                UiaAddToSelection(control, index);
            }
            catch (InvalidOperationException)
            {
                NativeAddToSelection(control, index);
            }
        }

        /// <summary>
        ///   Adds the list item to the current selection using UIA
        /// </summary>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="index"> Zero based index of the item. </param>
        private static void UiaAddToSelection(BaseProdControl control, int index)
        {
            if (!UiaCanSelectMultiple(control)) throw new ArgumentException("Does not support multiple selection");

            AutomationEventVerifier.Register(new EventRegistrationMessage(control,
                                                                          SelectionItemPattern.ElementAddedToSelectionEvent));

            LogController.ReceiveLogMessage(new LogMessage("Adding " + index));
            SelectionItemPatternHelper.AddToSelection(control.UIAElement);
        }

        /// <summary>
        ///   Adds the list item to the current selection using SendMessage
        /// </summary>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="index"> Zero based index of the item. </param>
        private static void NativeAddToSelection(BaseProdControl control, int index)
        {
            //NOTE: ProdListBoxNative.AddSelectedItemNative((IntPtr)control.UIAElement.Current.NativeWindowHandle, index);
        }

        /// <summary>
        ///   Adds the list item to the current selection.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="text"> The text of the item to select. </param>
        public static void AddToSelectionHook(this IList extension, BaseProdControl control, string text)
        {
            try
            {
                UiaAddToSelection(control, text);
            }
            catch (InvalidOperationException)
            {
                NativeAddToSelection(control, text);
            }
        }

        /// <summary>
        ///   Adds the list item to the current selection using UIA
        /// </summary>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="itemText"> The text of the item to select. </param>
        private static void UiaAddToSelection(BaseProdControl control, string itemText)
        {
            if (!UiaCanSelectMultiple(control)) throw new ArgumentException("Does not support multiple selection");

            AutomationEventVerifier.Register(new EventRegistrationMessage(control,
                                                                          SelectionItemPattern.ElementAddedToSelectionEvent));

            LogController.ReceiveLogMessage(new LogMessage("Adding " + itemText));
            SelectionItemPatternHelper.AddToSelection(control.UIAElement);
        }

        /// <summary>
        ///   Adds the list item to the current selection using SendMessage
        /// </summary>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="itemText"> The text of the item to select. </param>
        private static void NativeAddToSelection(BaseProdControl control, string itemText)
        {
            //NOTE: ProdListBoxNative.AddSelectedItemNative((IntPtr)control.UIAElement.Current.NativeWindowHandle, itemText);
        }

        /// <summary>
        ///   Removes the current element from the collection of selected items.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="index"> The index of the item to deselect. </param>
        public static void RemoveFromSelectionHook(this IList extension, BaseProdControl control,
                                                   int index)
        {
            try
            {
                UiaRemoveFromSelection(control, index);
            }
            catch (InvalidOperationException)
            {
                NativeRemoveFromSelection(control, index);
            }
        }

        private static void NativeRemoveFromSelection(BaseProdControl control, int index)
        {
            ProdListBoxNative.DeSelectItemNative((IntPtr)control.UIAElement.Current.NativeWindowHandle, index);
        }

        private static void UiaRemoveFromSelection(BaseProdControl control, int index)
        {
            if (!UiaCanSelectMultiple(control)) throw new ArgumentException("Does not support multiple selection");
            AutomationElement itemToSelect = SelectionItemPatternHelper.FindItemByIndex(control.UIAElement, index);
            AutomationEventVerifier.Register(new EventRegistrationMessage(control,
                                                                          SelectionItemPattern.ElementRemovedFromSelectionEvent));

            LogController.ReceiveLogMessage(new LogMessage("Removing " + index));
            SelectionItemPatternHelper.RemoveFromSelection(itemToSelect);
        }

        /// <summary>
        ///   Removes the current element from the collection of selected items.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <param name="text"> The text of the item to deselect. </param>
        public static void RemoveFromSelectionHook(this IList extension, BaseProdControl control,
                                                   string text)
        {
            try
            {
                UiaRemoveFromSelection(control, text);
            }
            catch (InvalidOperationException)
            {
                NativeRemoveFromSelection(control, text);
            }
        }

        private static void NativeRemoveFromSelection(BaseProdControl control, string itemText)
        {
            ProdListBoxNative.DeSelectItemNative((IntPtr)control.UIAElement.Current.NativeWindowHandle, itemText);
        }

        private static void UiaRemoveFromSelection(BaseProdControl control, string itemText)
        {
            if (!UiaCanSelectMultiple(control)) throw new ArgumentException("Does not support multiple selection");
            AutomationElement itemToSelect = SelectionItemPatternHelper.FindItemByText(control.UIAElement, itemText);
            AutomationEventVerifier.Register(new EventRegistrationMessage(control,
                                                                          SelectionItemPattern.ElementRemovedFromSelectionEvent));

            LogController.ReceiveLogMessage(new LogMessage("Removing " + itemText));
            SelectionItemPatternHelper.RemoveFromSelection(itemToSelect);
        }
        /// <summary>
        ///   Gets the list items.
        /// </summary>
        /// <param name="extension"> The extended interface. </param>
        /// <param name="control"> The UI Automation element </param>
        /// <returns> </returns>
        public static AutomationElementCollection GetItemsHook(this IList extension, BaseProdControl control)
        {
            return UiaGetItems(control);
        }

        private static AutomationElementCollection UiaGetItems(BaseProdControl control)
        {
            AutomationElementCollection convRet = SelectionPatternHelper.ListItems(control.UIAElement);
            Collection<object> retVal = InternalUtilities.AutomationCollToObjectList(convRet);
            LogController.ReceiveLogMessage(new LogMessage("List Items: ", retVal));
            return convRet;
        }

        /// <summary>
        ///   Gets the selected indexes.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        /// <returns> A List of all the indexes of currently selected list items. </returns>
        public static Collection<int> GetSelectedIndexesHook(this IList extension,
                                                             BaseProdControl control)
        {
            return UiaGetSelectedIndexes(control);
        }

        /// <summary>
        ///   Gets the selected indexes using UIA
        /// </summary>
        /// <param name="control"> The base ProdUI control </param>
        /// <returns> A List of all the indexes of currently selected list items. </returns>
        private static Collection<int> UiaGetSelectedIndexes(BaseProdControl control)
        {
            if (!UiaCanSelectMultiple(control)) throw new ArgumentException("Does not support multiple selection");

            AutomationElement[] selectedItems = SelectionPatternHelper.SelectedItems(control.UIAElement);
            Collection<object> retList = new Collection<object>
                                         {
                                             (selectedItems)
                                         };
            Collection<int> selectedIndexes = new Collection<int>();

            foreach (AutomationElement item in selectedItems)
            {
                retList.Add(SelectionItemPatternHelper.FindIndexByItem(control.UIAElement, item.Current.Name));
            }
            LogController.ReceiveLogMessage(new LogMessage("Selected Indexes", retList));
            return selectedIndexes;
        }

        /// <summary>
        ///   Selects all items in a ListBox.
        /// </summary>
        /// <param name="extension"> The extension interface. </param>
        /// <param name="control"> The base ProdUI control. </param>
        internal static void SelectAllHook(this ISelectionItem extension, BaseProdControl control)
        {
            UiaSelectAll(control);
        }


        private static void UiaSelectAll(BaseProdControl control)
        {
            if (!UiaCanSelectMultiple(control)) throw new ArgumentException("Does not support multiple selection");

            foreach (AutomationElement item in SelectionPatternHelper.ListItems(control.UIAElement))
            {
                SelectionItemPatternHelper.AddToSelection(item);
            }
        }

        public static bool CanSelectMultipleItemsHook(this IList extension, BaseProdControl control)
        {
            return UiaCanSelectMultiple(control);
        }

        private static bool UiaCanSelectMultiple(BaseProdControl control)
        {
            return SelectionPatternHelper.CanSelectMultiple(control.UIAElement);
        }
    }
}
